package com.goldfish666.remote_control.service.base;

import com.goldfish666.remote_control.exception.DataNotFoundException;
import com.goldfish666.remote_control.exception.ExistDataException;
import com.goldfish666.remote_control.repository.base.RepositoryWithKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;

import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;

public abstract class AbstractSimpleJpaService<TEntity, TRepository extends RepositoryWithKey<TEntity>> implements SimpleServiceWithKey<TEntity> {

    @Autowired
    protected TRepository repository;

    @Override
    public Page<TEntity> getPaged(Specification<TEntity> specification, Pageable pageable) {
        Page<TEntity> paged = repository.findAll(specification, pageable);
        return paged;
    }

    @Override
    public List<String> getIdsByFilter(Specification<TEntity> specification) {
        List<String> ids = repository.findAll(specification).stream().map(e -> {
            Field idField;
            try {
                idField = e.getClass().getDeclaredField("id");
                idField.setAccessible(true);
                Object id = idField.get(e);
                return (String) id;
            } catch (NoSuchFieldException | IllegalAccessException ex) {
                return null;
            }
        }).collect(Collectors.toList());
        return ids;
    }

    @Override
    public TEntity insert(TEntity entity) {
        try {
            TEntity saved = repository.saveAndFlush(entity);
            return saved;
        } catch (DataIntegrityViolationException dive) {
            throw new ExistDataException();
        }
    }

    @Override
    public TEntity update(TEntity entity) {
        TEntity saved = repository.saveAndFlush(entity);
        return saved;
    }

    @Override
    public TEntity save(TEntity entity) {
        TEntity saved = repository.saveAndFlush(entity);
        return saved;
    }

    @Override
    public List<TEntity> saveAll(List<TEntity> entities) {
        List<TEntity> saved = repository.saveAll(entities);
        return saved;
    }

    @Override
    public boolean delete(String id) {
        boolean result;
        try {
            repository.deleteById(id);
            result = true;
        } catch (Exception e) {
            result = false;
        }
        return result;
    }

    @Override
    public TEntity getById(String id) {
        TEntity entity = repository.findById(id).orElseThrow(DataNotFoundException::new);
        return entity;
    }

    @Override
    public List<TEntity> getAll() {
        List<TEntity> entities = repository.findAll();
        return entities;
    }
}